
package SSF.OS;

import com.renesys.raceway.SSF.*;

import java.io.*;

/** Superclass of SSF.OS.binaryTcpDump retained for backward compatibility.
 *  For better performance we now use SSF.OS.binaryTcpDump and user can afterwards
 *  convert to ASCII using SSF.OS.DumpPro.
 */
public class tcpDump {

  PrintWriter pw;
  Entity owner;

/** Create a tcpDump probe that writes to the given output stream. */
  public tcpDump(PrintWriter ostr,Entity ownedBy) {
    pw = ostr;
    owner = ownedBy;
  }

/** Dump the information of a single packet. */
  public void dump(PacketEvent pe) {
    pw.println(formatPacket(pe,owner.now()));
    pw.flush();
  }

/** Signify that the given packet has been dropped. */
  public void drop(PacketEvent pe) {
    pw.print("!D! ");
    dump(pe);
  }

/** Format packet header information as per 'tcpdump' conventions. */
  private static String formatPacket(PacketEvent pkt, long atTime) {
    String tstamp = formatTime(atTime);
    ProtocolMessage msg = pkt.getHeaders();
    if (msg instanceof IpHeader) {
      IpHeader iphdr = (IpHeader)msg;
      switch (iphdr.PROTOCOL_NO) {
      case Protocols.TCP_PRTL_NUM:
	TCP_Message tcpHdr = (TCP_Message)iphdr.payload();
	return 

	  (tstamp+" "+

	   IP_s.IPtoString(iphdr.SOURCE_IP)+"."+tcpHdr.SOURCE_port+

	   " > "+

	   IP_s.IPtoString(iphdr.DEST_IP)+"."+tcpHdr.DEST_port+
	   ": "+formatFlags(tcpHdr.flags)+" "+

	   ((tcpHdr.SEQno!=0 && tcpHdr.seglen!=0)?
	    (tcpHdr.SEQno+":"+(tcpHdr.SEQno+tcpHdr.seglen)+
	    "("+tcpHdr.seglen+") "):"")+

	    ((0 != (tcpHdr.flags & TCP_Header.ACK))?
	    ("ack "+ tcpHdr.ACKno):"")+

	   " win "+tcpHdr.AdvertisedWnd);
	
      default:
	return tstamp+" unknown protocol: "+
	  Protocols.getProtocolByNumber(iphdr.PROTOCOL_NO);
      }
    } else return (tstamp+" -- non-IP packet...");
  }

  private static String formatFlags(byte flags) {
     if (flags == 0) return ".";
     else {
       return 
	 (0 != (flags&TCP_Header.SYN)?"S":"")+
	 (0 != (flags&TCP_Header.FIN)?"F":"")+
	 (0 != (flags&TCP_Header.RST)?"R":"");
     }
  }

  private static String formatTime(long t) {
    // Automatically frequency-scales to Net frequency; 
    // timestamps reflect full precision

    long res = SSF.Net.Net.frequency;

    long ticks = 60*60*res; // initially: ticks per hour

    int hrs = (int)(t/ticks);
    t = t % ticks;
    ticks /= 60;

    int min = (int)(t/ticks);
    t = t % ticks;
    ticks /= 60;

    double sec = t*1./res;

    String fsec = (new Double(sec)).toString();
    int rlog = (int)(Math.log(res)/Math.log(10))+1;
    String pre = fsec.substring(0,fsec.indexOf("."));
    String post = fsec.substring(fsec.indexOf(".")+1);
    int E = post.indexOf("E");
    if (E>=0) {
      int exp = (new Integer(post.substring(E+2))).intValue();
      for (int x=0; x<exp-1; x++) 
	pre = "0" + pre ;
      post = post.substring(0,E);
      fsec = "0."+pre+post;
    } 

    return ((hrs<10?"0":"")+hrs+":"+
	    (min<10?"0":"")+min+":"+
	    (sec<10?"0":"")+fsec);
	    
  }
}

/*=                                                                      =*/
/*=  Copyright (c) 1997--2000  SSF Research Network                      =*/
/*=                                                                      =*/
/*=  SSFNet is open source software, distributed under the GNU General   =*/
/*=  Public License.  See the file COPYING in the 'doc' subdirectory of  =*/
/*=  the SSFNet distribution, or http://www.fsf.org/copyleft/gpl.html    =*/
/*=                                                                      =*/
